﻿// thread_2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <thread>
#include <thread>
#include <future>
#include <chrono>
#include <functional>
#include <atomic>
using namespace std;

#define LOG (printf("%s (%d) - <%s>\n",__FILE__,__LINE__,__FUNCTION__),printf)

#define log(format, ...)\
do{\
    time_t time_val=time(NULL);\
    char* ctr = ctime(&time_val);\
    ctr[24] = '\0';\
    printf("[%s] %s (%d) - <%s> : "#format " \n", ctr, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
}while(0)

void ThreadWork(shared_future<void> ft) {

	// 注意,线程只有执行到循环判断条件里才会中止,如果正在执行耗时任务,是不会停止的.
	//     所以这种通用的停止线程的模式也有弊端.
	while (ft.wait_for(chrono::milliseconds(1)) == future_status::timeout) {

		LOG("In ThreadWork thread id", this_thread::get_id());
		// 模拟执行耗时任务.  
		this_thread::sleep_for(chrono::milliseconds(1000));
	}
	LOG("ThreadWork END thread id", this_thread::get_id());
}

// 方式1：使用promise安全停止线程工作.
void TestThreadStop_1() {

	LOG("=========================== TestThreadStop_1 BEGIN ==============================");
	promise<void> p;
	shared_future<void> sp(p.get_future());

	auto result1 = std::async(std::launch::async, bind(ThreadWork, sp));
	auto result2 = std::async(std::launch::async, bind(ThreadWork, sp));

	// 让工作线程执行5秒钟
	this_thread::sleep_for(chrono::seconds(5));

	// 设置future状态为 future_status::ready,线程里的wait_for会返回值future_status::ready导致循环退出
	p.set_value();

	// 等待工作线程执行结束. 如果是线程调用,还需要优化停止方式.比如显示动画已表示正在停止中...
	result1.get();
	result2.get();
	LOG("TestThreadStop_1 END");
}


// 方式2：使用原子变量安全停止线程工作.
void TestThreadStop_2() {

	printf("=========================== TestThreadStop_2 BEGIN ==============================\n");
	atomic_bool stopped(false);
	int nCount = 0;
	auto func = [&](atomic_bool* ab) {
		while (!(*ab)) {
			printf("In lambda func thread id | %d | %d\n", this_thread::get_id(), nCount);
			// 模拟执行耗时任务.
			this_thread::sleep_for(chrono::milliseconds(3000));
			nCount++;
		}
		printf("lambda func END thread id | %d\n", this_thread::get_id());
	};

	auto result1 = std::async(std::launch::async, func, &stopped);
	auto result2 = std::async(std::launch::async, func, &stopped);

	// 让工作线程执行5秒钟
	this_thread::sleep_for(chrono::seconds(5));

	// 设置停止标记为true.
	stopped = true;

	// 等待工作线程执行结束. 
	result1.get();
	result2.get();
	printf("TestThreadStop_2 END\n");
}

// https://thispointer.com/c11-how-to-stop-or-terminate-a-thread/
int main(int argc, char const* argv[])
{
//	TestThreadStop_1();
	TestThreadStop_2();
	system("pause");
	return 0;
}

